package com.mf.service.impl.upload;

import com.mf.entity.bo.BasicResourceFileBo;
import com.mf.entity.request.upload.FileInitSliceDataReq;
import com.mf.entity.request.upload.FileUploadFileReq;
import com.mf.enums.EnumBasicResultCode;
import com.mf.service.upload.IBasicResourceFileService;
import com.mf.service.upload.IFileUploadBusiness;
import com.mf.service.upload.IFileUploadProcess;
import com.mf.utils.MinIOUtils;
import io.github.heollhai.common.config.exceptions.GraceException;
import io.github.heollhai.common.config.reids.RedisOperator;
import io.github.heollhai.common.utils.VerifyUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.UUID;

/**
 * @Author: lmf
 * @Create: 2024/11/20 21:13
 * Description: 文件上传服务实现类
 */
@Slf4j
@Service
public class FileUploadProcessImpl implements IFileUploadProcess {

    @Resource
    private IFileUploadBusiness fileUploadBusiness;
    @Resource
    private IBasicResourceFileService basicResourceFileService;

    @Resource
    private MinIOUtils minIOUtils;

    @Resource
    private RedisOperator redisOperator;


    @Override
    public void uploadFile(FileUploadFileReq fileUploadFileReq) {

        //--------------------文件-------------------------------
        MultipartFile file = fileUploadFileReq.getFile();
        //--------------------资源-------------------------------
        String md5 = fileUploadFileReq.getMd5();
        Integer totalIndex = fileUploadFileReq.getTotalIndex();
        Integer sliceIndex = fileUploadFileReq.getSliceIndex();

        // 文件全名
        String fullMd5Name = minIOUtils.getObjectName(fileUploadFileReq.getFileArea(), fileUploadFileReq.getFileBindId(),
                fileUploadFileReq.getFileType(), (md5 + fileUploadFileReq.getFileSuffix()));

        // 文件上传-不分片
        if (fileUploadFileReq.getIsSlice() == 0) {
            Boolean isWholeUpload = fileUploadBusiness.uploadFile(fileUploadFileReq.getBucketName(), fullMd5Name, file);
            if (!isWholeUpload) {
                GraceException.display(EnumBasicResultCode.UPLOAD_FILE_FAILED);
            }
            // 更新已上传状态信息到库里
            Boolean isUpdateSuccess = basicResourceFileService.updateFileUploadState(fileUploadFileReq);
            if (!isUpdateSuccess) {
                GraceException.display(EnumBasicResultCode.UPLOAD_UPDATEDB_FAILED);
            }
        }

        // 文件上传--分片
        if (fileUploadFileReq.getIsSlice() == 1) {
            log.debug("分片文件上传处理-------------");
            // 分片上传
            Integer sliceResult = fileUploadBusiness.uploadSliceFile(fullMd5Name, totalIndex, sliceIndex, file);
            // 完成所有的分片上传
            if (sliceResult.equals(-1)) {
                log.debug("已完成分片文件上传处理-------------");
                // 合并文件
                Boolean composeSuccess = fileUploadBusiness.composeFile(fileUploadFileReq.getBucketName(), fullMd5Name, totalIndex);

                // 文件合并失败提示
                if (!composeSuccess) {
                    GraceException.display(EnumBasicResultCode.UPLOAD_COMPOSE_FAILED);
                }

                // 更新已上传状态信息到库里
                Boolean isUpdateSucc = basicResourceFileService.updateFileUploadState(fileUploadFileReq);
                if (!isUpdateSucc) {
                    GraceException.display(EnumBasicResultCode.UPLOAD_UPDATEDB_FAILED);
                }

                // TODO 是否开一个线程单独处理它
                // 删除minio所有的分片文件
                fileUploadBusiness.delSliceFile(fullMd5Name, totalIndex);
            }
        }
    }

    /**
     * 初始化文件信息操作
     */
    @Override
    public void initFileData(FileInitSliceDataReq fileInitSliceDataReq) {
        Integer isSlice = fileInitSliceDataReq.getIsSlice();
        // 判断是否有minio桶，没有先创建桶
        Boolean isCreateBucket = fileUploadBusiness.createFileBucket(fileInitSliceDataReq.getBucketName());
        if (!isCreateBucket) {
            GraceException.display(EnumBasicResultCode.UPLOAD_BUCKET_FAILED);
        }

        if (basicResourceFileService.checkIsExistFile(fileInitSliceDataReq) != -2) {
            GraceException.display(EnumBasicResultCode.UPLOAD_FILE_EXIST);
        }

        // 初始化切片放入缓存
        if (isSlice == 1) {
            // 文件全名
            String fullMd5Name = minIOUtils.getObjectName(fileInitSliceDataReq.getFileArea(), fileInitSliceDataReq.getFileBindId(),
                    fileInitSliceDataReq.getFileType(), (fileInitSliceDataReq.getMd5() + fileInitSliceDataReq.getFileSuffix()));
            // 把分片的个数放入缓存
            Boolean isInRedis = fileUploadBusiness.sliceInRedis(fullMd5Name, fileInitSliceDataReq.getTotalSlice());
            if (!isInRedis) {
                GraceException.display(EnumBasicResultCode.UPLOAD_INIT_SLICE_FAILED);
            }
        }

        // 上传前先存储库
        BasicResourceFileBo resourceFile = BasicResourceFileBo.builder()
                .isUploaded(0)
                .minioMd5(fileInitSliceDataReq.getMd5())
                .minioBucket(fileInitSliceDataReq.getBucketName())
                .totalSlice(isSlice == 0 ? 0 : fileInitSliceDataReq.getTotalSlice())
                .originalFileName(fileInitSliceDataReq.getOriginalFileName())
                .sliceFileSize(isSlice == 0 ? 0 : fileInitSliceDataReq.getSliceFileSize())
                .fileSize(fileInitSliceDataReq.getFileSize())
                .fileType(fileInitSliceDataReq.getFileType())
                .fileArea(fileInitSliceDataReq.getFileArea())
                .fileBindId(fileInitSliceDataReq.getFileBindId())
                .remark(fileInitSliceDataReq.getRemark())
                .build();
        Boolean isFileInfoDB = basicResourceFileService.insertFile(resourceFile);
        if (!isFileInfoDB) {
            GraceException.display(EnumBasicResultCode.UPLOAD_FILE_FAILED);
        }
    }

    /**
     * 根据文件id，总切片(分片没有上传完需要)数删除
     */
    @Override
    public Integer deleteById(Integer id) {
        BasicResourceFileBo basicResourceFileBo = basicResourceFileService.selectById(id);
        if (VerifyUtils.isEmpty(basicResourceFileBo)) {
            GraceException.display(EnumBasicResultCode.FILE_NOT_EXIST);
        }
        basicResourceFileService.checkPermission(basicResourceFileBo.getFileType());

        // 获取minio文件名称
        final String objectName = minIOUtils.getObjectName(basicResourceFileBo.getFileArea(),
                basicResourceFileBo.getFileBindId(), basicResourceFileBo.getFileType(),
                (basicResourceFileBo.getMinioMd5() + minIOUtils.getFileSuffix(basicResourceFileBo.getOriginalFileName())));
        // 删除minio中文件
        Boolean isRemove = minIOUtils.removeFile(basicResourceFileBo.getMinioBucket(), objectName);
        if (!isRemove) {
            GraceException.display(EnumBasicResultCode.FILE_DELETE_FAILED);
        }
        // 删除数据库文件
        if (!basicResourceFileService.removeById(id)) {
            GraceException.display(EnumBasicResultCode.FILE_DELETE_FAILED);
        }

        // 没有上传完整并且是切片上传那么删除所有切片
        if (basicResourceFileBo.getTotalSlice() != 0 && basicResourceFileBo.getIsUploaded() == 0) {
            // 删除minio中的所有分片文件
            fileUploadBusiness.delSliceFile(objectName, basicResourceFileBo.getTotalSlice());
            // 删除redis中的缓存
            redisOperator.delete(objectName);
        }

        return 1;
    }
}
